package com.xiaoyudeguang.wrapper;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.toolkit.LambdaUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.xiaoyudeguang.context.SpringContext;
import com.xiaoyudeguang.mapper.BaseMapperImpl;

import java.util.Collection;
import java.util.function.Consumer;

/**
 * @author 赵光
 */
public class StreamLambdaQueryWrapper<T> extends BaseMapperImpl<LambdaQueryWrapper<T>, T> {

    public StreamLambdaQueryWrapper() {
        this(new LambdaQueryWrapper<T>(), null);
    }

    public StreamLambdaQueryWrapper(LambdaQueryWrapper<T> wrapper) {
        this(wrapper, null);
    }

    public StreamLambdaQueryWrapper(BaseMapper<T> baseMapper) {
        this(new LambdaQueryWrapper<T>(), baseMapper);
    }

    public StreamLambdaQueryWrapper(LambdaQueryWrapper<T> wrapper, BaseMapper<T> baseMapper) {
        super(wrapper, baseMapper);
    }

    /**
     * 等于
     */
    public StreamLambdaQueryWrapper<T> eq(SFunction<T, ?> column, Object value) {
        this.wrapper.eq(column, value);
        this.setEntityClass(column);
        return this;
    }

    /**
     * 等于
     */
    public StreamLambdaQueryWrapper<T> eq(boolean condition, SFunction<T, ?> column, Object value) {
        return !condition ? this : eq(column, value);
    }

    /**
     * 不等于
     */
    public StreamLambdaQueryWrapper<T> ne(SFunction<T, ?> column, Object value) {
        this.wrapper.ne(column, value);
        this.setEntityClass(column);
        return this;
    }

    /**
     * 不等于
     */
    public StreamLambdaQueryWrapper<T> ne(boolean condition, SFunction<T, ?> column, Object value) {
        return !condition ? this : ne(column, value);
    }

    /**
     * 大于
     */
    public StreamLambdaQueryWrapper<T> gt(SFunction<T, ?> column, Object value) {
        this.wrapper.gt(column, value);
        this.setEntityClass(column);
        return this;
    }

    /**
     * 大于
     */
    public StreamLambdaQueryWrapper<T> gt(boolean condition, SFunction<T, ?> column, Object value) {
        return !condition ? this : gt(column, value);
    }

    /**
     * 大于等于
     */
    public StreamLambdaQueryWrapper<T> ge(SFunction<T, ?> column, Object value) {
        this.wrapper.ge(column, value);
        this.setEntityClass(column);
        return this;
    }

    /**
     * 大于等于
     */
    public StreamLambdaQueryWrapper<T> ge(boolean condition, SFunction<T, ?> column, Object value) {
        return !condition ? this : ge(column, value);
    }

    /**
     * 小于
     */
    public StreamLambdaQueryWrapper<T> lt(SFunction<T, ?> column, Object value) {
        this.wrapper.lt(column, value);
        this.setEntityClass(column);
        return this;
    }

    /**
     * 小于
     */
    public StreamLambdaQueryWrapper<T> lt(boolean condition, SFunction<T, ?> column, Object value) {
        return !condition ? this : lt(column, value);
    }

    /**
     * 小于等于
     */
    public StreamLambdaQueryWrapper<T> le(SFunction<T, ?> column, Object value) {
        this.wrapper.le(column, value);
        this.setEntityClass(column);
        return this;
    }

    /**
     * 小于等于
     */
    public StreamLambdaQueryWrapper<T> le(boolean condition, SFunction<T, ?> column, Object value) {
        return !condition ? this : le(column, value);
    }

    /**
     * 模糊匹配
     */
    public StreamLambdaQueryWrapper<T> like(SFunction<T, ?> column, Object value) {
        this.wrapper.like(column, value);
        this.setEntityClass(column);
        return this;
    }

    /**
     * 模糊匹配
     */
    public StreamLambdaQueryWrapper<T> like(boolean condition, SFunction<T, ?> column, Object value) {
        return !condition ? this : like(column, value);
    }

    /**
     * 反向模糊匹配
     *
     * @return
     */
    public StreamLambdaQueryWrapper<T> notLike(SFunction<T, ?> column, Object value) {
        this.wrapper.notLike(column, value);
        this.setEntityClass(column);
        return this;
    }

    /**
     * 反向模糊匹配
     *
     * @return
     */
    public StreamLambdaQueryWrapper<T> notLike(boolean condition, SFunction<T, ?> column, Object value) {
        return !condition ? this : notLike(column, value);
    }


    /**
     * 向右模糊匹配
     */
    public StreamLambdaQueryWrapper<T> likeRight(SFunction<T, ?> column, Object value) {
        this.wrapper.likeRight(column, value);
        this.setEntityClass(column);
        return this;
    }

    /**
     * 向右模糊匹配
     */
    public StreamLambdaQueryWrapper<T> likeRight(boolean condition, SFunction<T, ?> column, Object value) {
        return !condition ? this : likeRight(column, value);
    }

    /**
     * 向左模糊匹配
     */
    public StreamLambdaQueryWrapper<T> likeLeft(SFunction<T, ?> column, Object value) {
        this.wrapper.likeLeft(column, value);
        this.setEntityClass(column);
        return this;
    }

    /**
     * 向左模糊匹配
     */
    public StreamLambdaQueryWrapper<T> likeLeft(boolean condition, SFunction<T, ?> column, Object value) {
        return !condition ? this : likeLeft(column, value);
    }

    /**
     * 存在
     */
    public StreamLambdaQueryWrapper<T> exists(SFunction<T, ?> column) {
        this.wrapper.isNotNull(column);
        this.setEntityClass(column);
        return this;
    }

    /**
     * 存在
     */
    public StreamLambdaQueryWrapper<T> exists(boolean condition, SFunction<T, ?> column) {
        return !condition ? this : exists(column);
    }

    /**
     * in
     *
     * @return
     */
    public StreamLambdaQueryWrapper<T> in(SFunction<T, ?> column, Object... values) {
        this.wrapper.in(column, values);
        this.setEntityClass(column);
        return this;
    }

    /**
     * in
     *
     * @return
     */
    public StreamLambdaQueryWrapper<T> in(boolean condition, SFunction<T, ?> column, Object... values) {
        return !condition ? this : in(column, values);
    }

    /**
     * in
     *
     * @return
     */
    public StreamLambdaQueryWrapper<T> in(SFunction<T, ?> column, Collection<?> values) {
        this.wrapper.in(column, values);
        this.setEntityClass(column);
        return this;
    }

    /**
     * in
     *
     * @return
     */
    public StreamLambdaQueryWrapper<T> in(boolean condition, SFunction<T, ?> column, Collection<?> values) {
        return !condition ? this : in(column, values);
    }

    /**
     * notIn
     *
     * @return
     */
    public StreamLambdaQueryWrapper<T> notIn(SFunction<T, ?> column, Object... values) {
        this.wrapper.notIn(column, values);
        this.setEntityClass(column);
        return this;
    }

    /**
     * notIn
     *
     * @return
     */
    public StreamLambdaQueryWrapper<T> notIn(boolean condition, SFunction<T, ?> column, Object... values) {
        return !condition ? this : lt(column, values);
    }

    /**
     * notIn
     *
     * @return
     */
    public StreamLambdaQueryWrapper<T> notIn(SFunction<T, ?> column, Collection<?> values) {
        this.wrapper.notIn(column, values);
        this.setEntityClass(column);
        return this;
    }

    /**
     * notIn
     *
     * @return
     */
    public StreamLambdaQueryWrapper<T> notIn(boolean condition, SFunction<T, ?> column, Collection<?> values) {
        return !condition ? this : lt(column, values);
    }

    /**
     * 区间
     *
     * @return
     */
    public StreamLambdaQueryWrapper<T> between(SFunction<T, ?> column, Object... values) {
        this.wrapper.between(column, values[0], values[1]);
        this.setEntityClass(column);
        return this;
    }

    /**
     * 区间
     *
     * @return
     */
    public StreamLambdaQueryWrapper<T> between(boolean condition, SFunction<T, ?> column, Object... values) {
        return !condition ? this : between(column, values);
    }

    /**
     * 为空
     */
    public StreamLambdaQueryWrapper<T> isNull(SFunction<T, ?> column) {
        this.wrapper.isNull(column);
        this.setEntityClass(column);
        return this;
    }

    /**
     * 为空
     */
    public StreamLambdaQueryWrapper<T> isNull(boolean condition, SFunction<T, ?> column) {
        return !condition ? this : isNull(column);
    }

    /**
     * 不为空
     */
    public StreamLambdaQueryWrapper<T> isNotNull(SFunction<T, ?> column) {
        this.wrapper.isNotNull(column);
        this.setEntityClass(column);
        return this;
    }

    /**
     * 不为空
     */
    public StreamLambdaQueryWrapper<T> isNotNull(boolean condition, SFunction<T, ?> column) {
        return !condition ? this : isNotNull(column);
    }

    /**
     * 或
     */
    public StreamLambdaQueryWrapper<T> or() {
        this.wrapper.or();
        return this;
    }

    /**
     * 或条件拼接
     */
    public StreamLambdaQueryWrapper<T> and(Consumer<StreamLambdaQueryWrapper<T>> consumer) {
        StreamLambdaQueryWrapper<T> streamLambdaQueryWrapper = new StreamLambdaQueryWrapper<>(this.wrapper);
        consumer.accept(streamLambdaQueryWrapper);
        return this;
    }

    private void setEntityClass(SFunction<T, ?> column) {
        if (column != null) {
            this.wrapper.setEntityClass((Class<T>) LambdaUtils.extract(column).getInstantiatedClass());
        }
    }

    @Override
    public BaseMapper<T> getMapper() {
        if (baseMapper != null) {
            return baseMapper;
        }
        if (wrapper.getEntityClass() == null) {
            throw new RuntimeException("请设置实体类");
        }
        return (BaseMapper<T>) SpringContext.getContext().getBean(StringUtils.firstToLowerCase(wrapper.getEntityClass().getSimpleName() + "Mapper"));
    }
}
